﻿using Grpc.Core;
using Grpc.Net.Client;
using Serilog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using static StudentServices;

namespace ConsoleApp_GrpcClient
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Log.Logger = new LoggerConfiguration()
                            .MinimumLevel.Debug()
                            .WriteTo.Console()
                            .CreateLogger();
            Log.Information($"{DateTime.UtcNow} 客服端程序启动。");

            using GrpcChannel channel = GrpcChannel.ForAddress("https://localhost:5001",
                new GrpcChannelOptions
                {
                    LoggerFactory = new SerialogLoggerLoggerFactory(),
                });
            StudentServicesClient client = new StudentServicesClient(channel);
            bool converFlagNu = int.TryParse(args.Length > 0 ? args[0].ToLower() : "4", out int choiceNu);
            Console.WriteLine($"轉化接受到的參數結果：{converFlagNu}");
            try
            {
                switch (choiceNu)
                {
                    case 1:
                        await UnitaryMethodRequestAsync(client);
                        break;
                    case 2:
                        await UnitaryMethodSaveStudentAsync(client);
                        break;

                    case 3:
                        await ClientStreamMethodAsync(client);
                        break;

                    case 4:
                        await ClientAndServerStreamMethodAsync(client);
                        break;

                    default:
                        Console.WriteLine($"未匹配到有效方法！");
                        break;
                }
            }
            catch (Exception ex)
            {
                Log.Fatal($"客户端运行出错 {ex.Message}");
            }
            
            Log.Information($"客户端程序执行完成！");
            Console.ReadKey();
        }

        private async static Task ClientAndServerStreamMethodAsync(StudentServicesClient client)
        {
            using var call = client.SaveMutilSudents();
            List<Student> studentsLs = new List<Student>()
            {
                new Student
                {
                    No=100,
                    Name="tom",
                    Address="usa",
                    Phone="123",
                },
                 new Student
                {
                    No=101,
                    Name="tom1",
                    Address="usa1",
                    Phone="123 1",
                },
                 new Student
                {
                    No=102,
                    Name="tom2",
                    Address="usa2",
                    Phone="123 2",
                },

            };
            //接收服务端发送过来的消息
            var responseTask = Task.Run(async () =>
            {
                while (await call.ResponseStream.MoveNext())
                {
                    if (call.ResponseStream.Current?.StudentInfo != null)
                    {
                        Console.WriteLine($"server send message {call.ResponseStream.Current?.StudentInfo}");
                    }
                    Console.WriteLine($"server send message {call.ResponseStream.Current?.IsOk}");
                }
            });

            foreach (var s in studentsLs)
            {
                //写入流
                await call.RequestStream.WriteAsync(new StudentRequest { CurRequestStudent = s });
            }
            //请求完成
            await call.RequestStream.CompleteAsync();
            //等待服务端返回结束
            await responseTask;
        }

        private async static Task ClientStreamMethodAsync(StudentServicesClient client)
        {
            //验证方式获取流
            using var call = client.SetHeadPhoto(CreateMetadataAndNo((DateTime.Now.Second % 15).ToString()));

            using var photoStream = new FileStream(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "1.jpg"), FileMode.Open, FileAccess.Read, FileShare.Read);

            byte[] atomBuf = new byte[1024];

            Random random = new Random();
            int id = random.Next(10);
            int no = random.Next(10);

            while (true)
            {
                int readNu = await photoStream.ReadAsync(atomBuf, 0, atomBuf.Length);
                if (readNu <= 0)
                {
                    break;
                }
                byte[] buf = new byte[readNu];
                Array.Copy(atomBuf, 0, buf, 0, buf.Length);
                var requestData = new StudentPhototRequest
                {
                    Data = Google.Protobuf.ByteString.CopyFrom(buf),
                };
                await call.RequestStream.WriteAsync(requestData);
            }
            //通知服务端完成流式写入
            await call.RequestStream.CompleteAsync();
            //拿到服务端的响应
            var response = await call.ResponseAsync;
            Console.WriteLine(response.CurResopnseStudent);
        }

        private async static Task UnitaryMethodSaveStudentAsync(StudentServicesClient client)
        {
            Random random = new Random();
            StudentRequest studentRe = new StudentRequest();
            studentRe.CurRequestStudent = new Student()
            {
                Id = random.Next(10),
                No = random.Next(100),
                Name = "龙浩天" + random.Next(10),
                Address = "家庭住址"
            };
            var result = await client.SaveStudentAsync(studentRe);
            Console.WriteLine(result);
        }

        /// <summary>
        /// 创建一个元数据，用于省份验证
        /// </summary>
        /// <returns></returns>
        static Metadata CreateMetadata()
        {
            Metadata me = new Metadata();
            me.Add(new Metadata.Entry("userName", "admin"));
            return me;
        }

        static Metadata CreateMetadataAndNo(string noStr)
        {

            Metadata md = CreateMetadata();
            md.Add(new Metadata.Entry("no", noStr));
            return md;

        }


        /// <summary>
        /// 一元方法调用请求
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        private static async Task UnitaryMethodRequestAsync(StudentServicesClient client)
        {
            Random random = new Random();
            StudentNoRequest studentNo = new StudentNoRequest()
            {
                No = random.Next(10),
            };
            var value = await client.GetStudentByNoAsync(studentNo, CreateMetadata());
            Console.WriteLine(value.CurResopnseStudent);
        }
    }
}
